#include <iostream>
#include "udpSocket.h"

/*
    服务端流程
        1、创建套接字端口  在内核中创建socket结构体，关联进程和网卡的联系
        2、为套接字绑定地址信息   socket结构体中必须有ip地址、端口、协议，告诉系统哪个ip、端口的数据给程序
        3、接受数据   系统受到需要给程序的数据后，会将此数据放到对应socket的接受缓冲区，然后服务器从接受缓冲区中取数据
        4、发送数据    将数据写入内核中的socket发送缓冲区中，系统选择合适的时机将数据封装发送
        5、关闭套接字    释放资源
    
    socket接口
        创建套接字 int socket(int domain, int type, int protocol)
            domain 地址域 本地通信 AF_LOCAL, ipv4 AF_INET, ipv6 AD_INET6
            type 套接字类型 流式套接字 SOCK_STREAM, 数据报套接字 SOCK_DGRAM
            protocol 协议类型  tcp IPPROTO_TCP, UDP IPPROTO_UDP  
            失败返回-1，成功返回文件描述符-非负整数，套接字所有其他接口的操作句柄
        
        绑定地址信息 int bind(int sockfd, struct sockaddr *addr, socklen_t len)
            sockfd 创建套接字返回的操作句柄
            addr 要绑定的地址信息
            len 要绑定的地址信息长度 

        接收数据，接收发送者地址便于回复 ssize_t recvfrom(int sockfd, char *buf, int len, int flag, struct sockaddr *peer_addr, socklen *addr)
            sockfd 创建套接字返回的操作句柄
            buf 缓冲区，用于接收从接收缓冲区中取出的数据
            len 要接收的数据长度
            flag 操作选项标志，默认为0，表示阻塞操作
            peer_addr 发送方的地址信息
            addrlen 想要获取的地址信息长度及实际长度
            成功返回实际接收到的数据字节长度，失败返回-1
        
        发送数据 ssize_t sendto(int sockfd, char *data, int len, int flag, struct sickaddr *peer_addr, socklen_t addrlen)
            sockfd 创建套接字返回的操作句柄
            data 要发送的数据地址
            len 要发送数据长度
            flag 默认为0，阻塞操作
            peer_addr 接收方的地址信息
            addrlen 地址信息擦痕嗯度
            成功返回实际发送的数据字节长度，失败返回-1
        
        关闭套接字 int close(int sockfd)

        网络字节序的转换接口
        uint32_t htonl(uint32_t hostlong) 主机字节序到网络字节序的转换
        uint16_t htons(uint16_t hostshort)
        uint32_t ntohl(uint32_t netlong)网络字节序到主机字节序的转换
        uint16_t ntohs(uint16_t netshort)

        in_addr_t inet_addr(const char *cp)将字符串的点分十进制IP地址转换成为网络字节序的整数IP地址
        char *inet_ntoa(struct in_addr in)将网络字节序的整数IP地址转化为字符串点分十进制IP地址
        const char *inet_ntop(int af, const void *src,char *dst, socklen_t size)将网络字节序的整数IP地址转化为字符串IP地址-兼容IPv4和IPv6
        int inet_pton(int af, const char *src, void *dst)将字符串的IP地址转换成为网络字节序的整数IP地址-兼容IPv4和IPv6
*/

int main(int argc, char *argv[])
{
	//运行时有三个参数 server-demo 192.168.73.29 4096
	if (argc != 3)
	{
		std::cout << "Usage: ./server-demo ip prot\n";
		return -1;
	}
	uint16_t port = std::stoi(argv[2]);
	std::string ip = argv[1];
	UdpSocket serverSocket;
	//创建套接字
	bool ret = serverSocket.Socket();
    if(!ret)
    {
        std::cout << "socket err" << std::endl;
        return -1;
    }
	//绑定地址信息
	serverSocket.Bind(ip, port);
	while(true)
	{
		//接收数据
		std::string buf;
		std::string peer_ip;
		uint16_t peer_port;
		serverSocket.Recv(&buf, &peer_ip, &peer_port);
		std::cout << "client["<<peer_ip<<":"<<peer_port<<"] say: " << buf << std::endl;

        if(buf == "quit")
        {
            break;
        }

		//发送数据
		buf.clear();
		std::cout << "server say: ";
		std::cin >> buf;
        if(buf == "quit")
        {
            break;
        }
		serverSocket.Send(buf, peer_ip, peer_port);
	}
	//关闭套接字
	serverSocket.Close();
	return 0;
}




